%{
#include <stdio.h>
int yylex();
int yydebug=1;
int errors = 0;
int linhas = 1;
int errorMes = 0;

int coment = 0;
%}

%start programa

%token PBEGIN
%token CONST
%token DOIS_PONTOS
%token END
%token IDENT
%token IGUAL
%token INTEGER 
%token PONTO
%token PONTO_VIRGULA
%token PROGRAM 
%token PROCEDURE
%token REAL
%token VAR
%token VIRGULA
%token ABRE_PARANTESES
%token FECHA_PARANTESES
%token ELSE
%token READLN
%token WRITELN
%token REPEAT 
%token UNTIL
%token IF 
%token THEN 
%token ATRIBUICAO
%token WHILE 
%token DO 
%token DIFERENTE
%token MAIOR_IGUAL
%token MENOR_IGUAL
%token MAIOR
%token MENOR
%token SINAL_MAIS
%token SINAL_MENOS
%token SINAL_MULTI
%token SINAL_DIV
%token COMENTARIO
%token ABRE_COMENTARIO
%token FECHA_COMENTARIO

%%
programa        : PROGRAM IDENT PONTO_VIRGULA corpo PONTO {yyerrok;}

                | error IDENT PONTO_VIRGULA 
			{ yyerror("Programa mal iniciado"); yyclearin; yyerrok;} 
				corpo PONTO 

                | PROGRAM error PONTO_VIRGULA 
			{ yyerror("identificador esperado"); yyclearin; yyerrok;} 
				corpo PONTO
                | PROGRAM IDENT 
                        error{ yyerror("';' esperado"); yyclearin; yyerrok;}  
                                corpo PONTO

                | PROGRAM IDENT PONTO_VIRGULA corpo 
                        error{ yyerror("'.' esperado ao final do programa"); yyclearin; yyerrok;} 
				
		;
///////////////////////////////////////////////////////////////////////////////////////////////ok
corpo		: dc PBEGIN comandos END

		| dc error PBEGIN comandos END
			{ yyerror("begin esperado"); yyclearin; yyerrok;}  // se não tiver begin, reconhece que não tem,
									   // mas buga reconhecimento de outros erros

		| dc PBEGIN comandos 
			error{yyerror("end esperado"); yyclearin; } 		
			

		;
////////////////////////////////////////////////////////////////////////////////////////////////ok
dc		: dc_c dc_v dc_p


		| error IDENT IGUAL numero PONTO_VIRGULA
			{  yyerror("const esperado"); yyclearin; yyerrok;}   			
				  dc_c dc_v dc_p


		| dc_c
			error { yyerror("var esperado"); yyerrok;} variaveis DOIS_PONTOS tipo_var PONTO_VIRGULA
			  // só imprime "syntax error"
				 dc_v dc_p

		| dc_c dc_v 
			error IDENT parametros PONTO_VIRGULA
			{ yyerror("'procedure' esperado"); yyerrok;}  
					   corpo_p dc_p	
				
	
		;
//////////////////////////////////////////////////////////////////////////////////////////////ok 
dc_c		: CONST IDENT IGUAL numero PONTO_VIRGULA dc_c

		|CONST error IGUAL numero PONTO_VIRGULA
			{  yyerror("identificador esperado"); yyclearin; yyerrok;}   			
				  dc_c

		|CONST IDENT error numero PONTO_VIRGULA
			{ yyerror("'=' esperado"); yyclearin; yyerrok;}  		
				  dc_c

		|CONST IDENT IGUAL error PONTO_VIRGULA
			{ yyerror("numero esperado"); yyclearin; yyerrok;}  		
				  dc_c

		|CONST IDENT IGUAL numero error 
			{ yyerror("';' esperado"); }		
				  dc_c

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////ok
dc_v		: VAR variaveis DOIS_PONTOS tipo_var PONTO_VIRGULA dc_v


		| VAR error DOIS_PONTOS tipo_var PONTO_VIRGULA
			{yyerror("identificador esperado"); yyerrok;}
				 dc_v
			

		| VAR variaveis error tipo_var PONTO_VIRGULA
			{ yyerror("':' esperado"); yyerrok;}  		
				  dc_v

		|VAR variaveis DOIS_PONTOS error { yyerror("tipo de variavel esperado");} 
			PONTO_VIRGULA dc_v		

		|VAR variaveis  DOIS_PONTOS tipo_var 
			error{ yyerror("';' esperada"); yyerrok;}			
				 dc_v			

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////ok
tipo_var	: REAL
 
		| INTEGER
		
		;
//////////////////////////////////////////////////////////////////////////////////////////ok
variaveis	: IDENT mais_var
		;
//////////////////////////////////////////////////////////////////////////////////////////ok
mais_var	: VIRGULA variaveis

		| tipo_var mais_par error{yyerror("':' esperado"); yyerrok;}//Mudeeeeeeeeeeeeeeeeeei

		| error{yyerror("',' esperada"); yyerrok;}
			variaveis
		
		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////ok 
dc_p		: PROCEDURE IDENT parametros PONTO_VIRGULA corpo_p dc_p	

		| PROCEDURE error parametros PONTO_VIRGULA
			{ yyerror("identificador de procedimento esperado"); yyerrok;}  
					  corpo_p dc_p

		| PROCEDURE IDENT parametros error

			{ yyerror("';' esperado"); yyerrok;}		 	
				corpo_p dc_p

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////////////////ok
parametros	: ABRE_PARANTESES lista_par FECHA_PARANTESES  				

		| error{yyerror("'(' esperado"); yyerrok;}
			lista_par FECHA_PARANTESES

		// não reconhece falta de ')'

		| /*vazio*/

		;
///////////////////////////////////////////////////////////////////////////////////////////////////////ok 
lista_par	: variaveis DOIS_PONTOS tipo_var mais_par

		| variaveis

		//| variaveis error {yyerror("':' esperado"); yyerrok;} tipo_var mais_par
				  // loop infinito

		| error{yyerror("identificador esperado"); yyerrok;}
			DOIS_PONTOS tipo_var mais_par

		// não reconhece falta de tipo de parametro

		;
//////////////////////////////////////////////////////////////////////////////////////////////////////ok
mais_par	: PONTO_VIRGULA lista_par

		| error{yyerror("';' esperado"); yyerrok;}
			lista_par

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////////////////////ok
corpo_p		: dc_loc PBEGIN comandos END PONTO_VIRGULA

		| dc_loc comandos
			error{yyerror("begin esperado"); yyerrok;}
				END PONTO_VIRGULA
			
		| dc_loc PBEGIN comandos
			error{ yyerror("end esperado"); yyerrok;} 	
			 	 PONTO_VIRGULA

		| dc_loc PBEGIN comandos END
			error{ yyerror("';' esperado"); yyerrok;}		
		;
//////////////////////////////////////////////////////////////////////////////////////ok
dc_loc		: dc_v	
			
		;
/////////////////////////////////////////////////////////////////////////////////////ok 
lista_arg	: ABRE_PARANTESES argumentos FECHA_PARANTESES 
	
		| error{yyerror("'(' esperado"); yyerrok;}
			argumentos FECHA_PARANTESES

		|  ABRE_PARANTESES argumentos 
			error{ yyerror("')' esperado"); yyerrok;} 			
		
		| /*vazio*/

		;
////////////////////////////////////////////////////////////////////////////////////////ok
argumentos	: IDENT mais_ident

		| error{yyerror("identificador esperado"); yyerrok;}
			mais_ident

		;
/////////////////////////////////////////////////////////////////////////////////////////ok
mais_ident	: PONTO_VIRGULA argumentos

		| error{yyerror("';' esperado");}
			argumentos
	
		| /*vazio*/

		;
///////////////////////////////////////////////////////////////////////////////////////ok
pfalsa		: ELSE cmd

		| error{yyerror("else esperado");}
			cmd

		| /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////ok
comandos 	: cmd PONTO_VIRGULA {yyerrok;} comandos

		| cmd 
			error{ yyerror("';' esperado"); yyerrok;}		 
				 comandos

		|  /*vazio*/

		;
//////////////////////////////////////////////////////////////////////////////////////ok +- E se faltar ')'
cmd 		: READLN ABRE_PARANTESES variaveis FECHA_PARANTESES

		| READLN variaveis 
			error{yyerror("'(' esperado"); yyerrok;}
				FECHA_PARANTESES

		| READLN ABRE_PARANTESES variaveis
				error{yyerror("')' esperado"); }  // tá entrando na regra do mais_var e por isso fica dando
								  // msg de ',' esperada
					

		| READLN ABRE_PARANTESES 
				error{yyerror("identificador esperado"); }
					FECHA_PARANTESES
					
///////////////////////////ok +- E se faltar ')'
		| WRITELN ABRE_PARANTESES variaveis FECHA_PARANTESES

		| WRITELN variaveis 
			error{yyerror("'(' esperado"); yyerrok;}
				FECHA_PARANTESES

		| WRITELN ABRE_PARANTESES variaveis
				error{yyerror("')' esperado"); }  // tá entrando na regra do mais_var e por isso fica dando
								  // msg de ',' esperada

		| WRITELN ABRE_PARANTESES 
				error{yyerror("identificador esperado"); }
					FECHA_PARANTESES

////////////////////////////ok 
		| REPEAT comandos UNTIL condicao

		| REPEAT comandos error 
			{yyerror("until esperado"); } condicao // reconhece, mas reconhece também vários erros que não existem
					
////////////////////////////
		| IF condicao THEN cmd pfalsa

		| IF condicao
			error{ yyerror("then esperado"); yyerrok;} 
				 cmd pfalsa
///////////////////////////ok
		
		| IDENT ATRIBUICAO expressao 

		| IDENT error
			{ yyerror("':=' esperado"); yyerrok;}  expressao // não reconhece e reconhece também vários erros que não 
									      //existem

//////////////////////////ok
		| IDENT lista_arg 

		| error
			{ yyerror("identificador esperado"); yyerrok;} lista_arg

/////////////////////////ok
		| PBEGIN comandos END

		| error PBEGIN comandos END 
			{ yyerror("begin esperado"); yyerrok;}  // não reconhece e reconhece também vários erros que não existem

		| PBEGIN comandos error 
			{ yyerror("end esperado"); } // tá entrando na regra errada

//////////////////////////////////////////ok
		| WHILE ABRE_PARANTESES condicao FECHA_PARANTESES DO cmd 

		| WHILE 
			error{yyerror("'(' esperado"); yyclearin; yyerrok;}  // bugado
				condicao FECHA_PARANTESES DO cmd

		| WHILE ABRE_PARANTESES	condicao FECHA_PARANTESES
			error{yyerror("'do' esperado"); yyerrok;}
				cmd

		| WHILE ABRE_PARANTESES	condicao DO
			error{yyerror("')' esperado"); yyerrok;}
				cmd

		| WHILE ABRE_PARANTESES DO 
			error{yyerror("comando while mal formado"); yyerrok;}
				cmd

		| WHILE ABRE_PARANTESES  
			error{yyerror("comando while mal formado"); yyerrok;}
				cmd	
		
		| WHILE 
			error{yyerror("comando while mal formado"); yyerrok;}
				cmd

		| WHILE FECHA_PARANTESES
			error{yyerror("comando while mal formado"); yyerrok;}
				cmd

		| WHILE FECHA_PARANTESES DO
			error{yyerror("comando while mal formado"); yyerrok;}
				cmd

		| WHILE condicao
			error{yyerror("comando while mal formado"); yyerrok;}
				cmd

		// não reporta erro caso não haja comando

		;
///////////////////////////////////////////////////////////////ok
condicao	: expressao relacao expressao

		| error{yyerror("condição esperada"); yyerrok;}
		
		;
////////////////////////////////////////////////////////////////ok
relacao		: IGUAL 
		| DIFERENTE 
		| MAIOR_IGUAL
		| MENOR_IGUAL
		| MAIOR
		| MENOR

		| error{yyerror("relação desconhecida"); yyclearin;} 		
	
		;
///////////////////////////////////////////////////////////////////ok
expressao	: termo outros_termos
		
		| error{yyerror("termo esperado"); yyerrok;}		
		
		;
/////////////////////////////////////////////////////////////////ok +- E se não conhecer operador
op_un		: SINAL_MAIS

		| SINAL_MENOS	

		| /*vazio*/
		;
/////////////////////////////////////////////////////////////////ok
outros_termos	: op_ad termo outros_termos
		| /*vazio*/
		;
////////////////////////////////////////////////////////////ok
op_ad		: SINAL_MAIS
		| SINAL_MENOS

		| error{yyerror("operador desconhecido"); yyclearin; yyerrok;}

		;
////////////////////////////////////////////////////////////////ok
termo 		: op_un fator mais_fatores		
		;
///////////////////////////////////////////////////////////////ok
mais_fatores 	: op_mul fator mais_fatores
		| /*vazio*/
		;
////////////////////////////////////////////////////////////ok
op_mul 		: SINAL_MULTI
		| SINAL_DIV

		| error{yyerror("operador desconhecido"); yyclearin; yyerrok;}

		;
//////////////////////////////////////////////////////////////ok +- Parênteses mal formados
fator		: IDENT
		| numero
		| ABRE_PARANTESES expressao FECHA_PARANTESES

		| error{yyerror("identificador esperado"); yyerrok;}

		;
////////////////////////////////////////////////////////////ok
numero		: INTEGER
		| REAL

		| error{ yyerror("tipo numérico não conhecido"); yyerrok;} 
		
		;
		

%%
#include "lex.yy.c"

int main(){

  tab_sim = (simbo*) malloc(MAX_SIMBO*sizeof(simbo));
  inicializaTipo(tab_tipo);
  inicializaPalavrasReservadas(reservadas);
	
  yyparse();

  if(coment == 1){
	printf("Comentário não fechado\n");
	errorMes = 1;
  }
		

  if(!errorMes)
	printf("\nCompilado com sucesso\n\n");
	

return 0;
}

yyerror(char *s){

	errorMes  = 1;
	printf("%d: %s\n", yylineno, s);
}

























	
